package main

import (
	"bufio"
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net/url"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/go-redis/redis/v8"
)

type Msg struct {
	Pf      string
	TaskId  int
	Account string
	Result  int
	Err     string
}

func (m *Msg) Encode() string {
	v := url.Values{}
	v.Set("p", m.Pf)
	v.Set("t", strconv.Itoa(m.TaskId))
	v.Set("a", m.Account)
	v.Set("r", strconv.Itoa(m.Result))
	v.Set("e", m.Err)
	return v.Encode()
}

func (m *Msg) Decode(s string) error {
	v, err := url.ParseQuery(s)
	if err != nil {
		return err
	}
	m.Pf = v.Get("p")
	m.TaskId, err = strconv.Atoi(v.Get("t"))
	if err != nil {
		return err
	}
	m.Account = v.Get("a")
	m.Result, err = strconv.Atoi(v.Get("r"))
	if err != nil {
		return err
	}
	m.Err = v.Get("e")
	return nil
}

var (
	// 使用 sync.Map 来缓存 LPUSH 的 value
	cache = sync.Map{}
	// 定义命令行标志
	filePath         = flag.String("file", "", "文件路径")
	lpushKey         = flag.String("lpushKey", "", "Redis的LPUSH键")
	rpopKey          = flag.String("rpopKey", "", "Redis的RPOP键")
	pf               = flag.String("pf", "", "pf参数")
	redisAddr        = flag.String("addr", "localhost:6379", "Redis服务器地址和端口")
	redisPassword    = flag.String("password", "", "Redis连接的密码")
	validPhoneNumber []string
)

func main() {

	flag.Parse()

	// 检查必需的参数
	if *filePath == "" || *lpushKey == "" || *rpopKey == "" || *pf == "" {
		fmt.Println("请提供文件路径、LPUSH键、RPOP键和pf参数")
		return
	}

	// 创建Redis客户端
	client := redis.NewClient(&redis.Options{
		Addr:     *redisAddr,
		Password: *redisPassword,
		DB:       0,
	})

	// 创建等待组以等待协程完成
	var wg sync.WaitGroup
	wg.Add(2)

	// 启动协程读取文件并插入Redis
	go func() {
		defer wg.Done()

		file, err := os.Open(*filePath)
		if err != nil {
			log.Println("打开文件出错:", err)
			return
		}
		defer file.Close()

		scanner := bufio.NewScanner(file)
		index := 0
		for scanner.Scan() {
			phoneNumber := scanner.Text()
			msg, value := generateValue(phoneNumber, *pf)
			err := client.LPush(context.Background(), *lpushKey, value).Err()
			if err != nil {
				log.Println("插入Redis出错:", err)
			} else {
				log.Println("成功插入数据:", value, "索引：", index)
				// 将 value 缓存到 sync.Map 中
				cache.Store(msg.TaskId, index)
				index = index + 1
			}
		}

		if err := scanner.Err(); err != nil {
			log.Println("读取文件出错:", err)
		}
	}()

	// 启动协程从另一个Redis列表中读取数据并匹配
	go func() {
		defer wg.Done()

		// 创建Redis客户端用于读取另一个列表的数据
		anotherClient := redis.NewClient(&redis.Options{
			Addr:     *redisAddr,
			Password: *redisPassword,
			DB:       0,
		})

		for {
			// 从另一个列表中阻塞式获取数据
			result, err := anotherClient.BRPop(context.Background(), time.Minute, *rpopKey).Result()
			if err != nil {
				if err == redis.Nil {
					// 当超时时间到达时，返回 redis.Nil 错误
					fmt.Println("超时")
					break
				}
				log.Printf("从另一个列表中获取数据出错:%+v\n", err)
				continue
			}

			// 解码获取的数据
			msg := &Msg{}
			err = msg.Decode(result[1])
			if err != nil {
				log.Println("解码获取的数据出错:", err)
				continue
			}

			// 匹配获取的数据与之前插入的数据
			matchData(msg)
		}
	}()

	fmt.Println("等待插入数据和匹配结果...")
	wg.Wait()

	fmt.Println("剩余还没有匹配上的数据有...")
	cache.Range(func(key, value interface{}) bool {
		fmt.Printf("Key: %v, Value: %v\n", key, value)
		return true // 返回 true 继续遍历，返回 false 停止遍历
	})

	_ = os.WriteFile("outfile.txt", []byte(strings.Join(validPhoneNumber, "")), os.FileMode(0666))
	return
}

// 生成插入Redis的value
func generateValue(phoneNumber, pf string) (*Msg, string) {
	timestamp := time.Now().Nanosecond()
	msg := &Msg{
		Pf:      pf,
		TaskId:  int(timestamp), // 使用0作为示例，根据实际情况修改
		Account: phoneNumber,
		Result:  0, // 使用0作为示例，根据实际情况修改
		Err:     "",
	}
	return msg, msg.Encode()
}

// 匹配获取的数据与之前插入的数据
func matchData(msg *Msg) {
	// 生成匹配的value
	//timestamp := time.Now().Unix()
	//msg.Pf = pf
	//msg.TaskId = int(timestamp) // 使用0作为示例，根据实际情况修改
	//msg.Result = 0              // 使用0作为示例，根据实际情况修改
	//msg.Err = ""

	// 编码消息为字符串
	value := msg.Encode()

	// 检查缓存中是否存在匹配的 value
	index, found := cache.Load(msg.TaskId)
	if found {
		if msg.Result == 1 {
			validPhoneNumber = append(validPhoneNumber, fmt.Sprintf("%v%c%c", msg.Account, 0x0D, 0x0A))
		}
		fmt.Printf("插入的数据:(索引:%v , 内容:%s) 结果为: 匹配,筛料结果为:%v\n", index, value, msg.Result == 1)
		// 删除匹配的 key
		cache.Delete(msg.TaskId)
	} else {
		b, _ := json.Marshal(msg)
		fmt.Printf("插入的数据:(索引:%v , 内容:%s) 结果为: 不匹配（结果：%s）\n", index, value, string(b))
	}
}
